#ifndef UTILS_H
#define UTILS_H
#include <iostream>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <queue>
#include <stdint.h>
#include <time.h>
#define IA 16807
#define IM 2147483647
#define AM (1.0/IM)
#define IQ 127773
#define IR 2836
#define MASK 123459876
using namespace std;

static long kSeed_arrival = time(NULL);				//seed for the generating the interarrival times
static long kSeed_service = time(NULL) + 10467;		//seed for the generating the service times

//Customer structure
typedef struct Customer {
	uint32_t id_;					//the customer ID
	double arrival_time_;			//the arrival time
	double service_time_;			//the service time
	double waiting_time_;			//the waiting time
	double departure_time_;			//the departure time
	uint32_t customers_after_;		//the number of customers in the system immediately after this customer 
	bool lost_, serviced_;			//flags to indicate whether the customer has been served yet, or has 									 
									//been lost
	uint32_t departure_number_;
	//constructor to initialize a Customer
	Customer(uint32_t id, double arrival_time, double service_time,
			double waiting_time, double departure_time,
			bool serviced, bool lost) : id_(id), arrival_time_(arrival_time),
	service_time_(service_time), waiting_time_(waiting_time), departure_time_(departure_time),
	serviced_(serviced), lost_(lost) {
		customers_after_ = 0;
		departure_number_ = -1;
	}
	//utility function to print the customer information
	void print() {
		cout << "Id : " << id_ << ", Arrival time = " << arrival_time_
			<< ", Service time = " << service_time_
			<< ", Waiting time = " << waiting_time_
			<< ", Departure time = " << departure_time_
			<< ", Lost = " << lost_
			<< ", serviced = " << serviced_ 
			<< ", customers after = " << customers_after_ << endl;
	}
}Customer;

typedef struct EventNode {
	char type_;						//event type ('A', 'D' or 'L')
	Customer *customer_;			//pointer to the corresponding customer
	double time_;					//the time of the event
	//constructor to initialize an event
	EventNode(char type, Customer *customer, double time) : type_(type),
	customer_(customer), time_(time) {
	}
	//utility function to print the event information
	void print() {
		if (customer_ != NULL) {
			cout << "Type : " << type_ << ", id : " << customer_->id_
				<< ", time : " << time_ << endl; //<< ", queue size = " << customer_queue.size() << endl;
		}
	}

}EventNode;

//function to generate the random number in the range (0, 1), given a seed
double ran0(long *idnum) {
	long k;      
	double ans;

	*idnum ^= MASK;
	k = (*idnum)/IQ;
	*idnum = IA * (*idnum - k * IQ) - IR * k;
	if (*idnum < 0) {
		*idnum += IM;
	}
	ans = AM * (*idnum);
	*idnum ^= MASK;
	return ans;
}

//function to generate an exponentially distributed random number with mean 1
double expdev(long *idnum) {
	double dummy;
	do {
		dummy = ran0(idnum);
	} while (dummy == 0.0);
	return -log(dummy);
}

//function to generate an exponentially distributed random number with mean "mean"
double expntl(double mean, long &seed) {
	return 1.0 * mean * expdev(&seed);
}

#endif
